/**
 * @file packset.c
 * @author MaxwellWang
 * @brief 
 * @version v1.0.0
 * @date 2025/11/25
 * @copyright Copyright (c) 2025
 * this file is part of the mw-iap firmware
*/
#include <string.h>
#include "packet.h"
#include "crc.h"
#include "flash_helper.h"
// Private functions
#ifdef packe_try
static int try_decode_packet(unsigned char *buffer, unsigned int in_len,
		void(*process_func)(unsigned char *data, unsigned int len), int *bytes_left);
/**
 * @brief pack initial&reset
 * 
 * 
*/
void packet_init(void(*s_func)(unsigned char *data,unsigned int len),void(*p_func)(unsigned char *data,unsigned int len),packset_state_t *state){
    memset(state,0,sizeof(packset_state_t));
    state->send_func = s_func;
    state->process_func = p_func;
}
void packset_reset(packset_state_t *state){
    state->rx_read_ptr = 0;
    state->rx_write_ptr = 0;
    state->bytes_left = 0;
}
/**
 * @brief packset sende normally packet
 * 
 * 
*/
void packet_send(unsigned char *data, unsigned int len, packset_state_t *state) {
	if (len == 0 || len > PACKET_MAX_PL_LEN) {
		return;
	}

	int b_ind = 0;

	if (len <= 255) {
		state->tx_buffer[b_ind++] = 2;
		state->tx_buffer[b_ind++] = len;
	} else if (len <= 65535) {
		state->tx_buffer[b_ind++] = 3;
		state->tx_buffer[b_ind++] = len >> 8;
		state->tx_buffer[b_ind++] = len & 0xFF;
	} else {
		state->tx_buffer[b_ind++] = 4;
		state->tx_buffer[b_ind++] = len >> 16;
		state->tx_buffer[b_ind++] = (len >> 8) & 0xFF;
		state->tx_buffer[b_ind++] = len & 0xFF;
	}

	memcpy(state->tx_buffer + b_ind, data, len);
	b_ind += len;

	unsigned short crc = crc16(data, len);
	state->tx_buffer[b_ind++] = (uint8_t)(crc >> 8);
	state->tx_buffer[b_ind++] = (uint8_t)(crc & 0xFF);
	state->tx_buffer[b_ind++] = 3;

	if (state->send_func) {
		state->send_func(state->tx_buffer, b_ind);
	}
}
/**
 * @brief process byte
 * 
 * 
*/
void packet_process_byte(uint8_t rx_data,packset_state_t *state){
    unsigned int data_len = state->rx_write_ptr - state->rx_read_ptr;
    //Out of space(should not happen)
    if(data_len>=PACKET_BUFFER_LEN){
        state->rx_write_ptr = 0;
        state->rx_read_ptr = 0;
        state->bytes_left = 0;
        state->rx_buffer[state->rx_write_ptr++] = rx_data;
        return;
    }
    if(state->rx_write_ptr>=PACKET_MAX_PL_LEN){
        memmove(state->rx_buffer,state->rx_buffer+state->rx_read_ptr,data_len);
        state->rx_read_ptr = 0;
        state->rx_write_ptr = data_len;
    }
    state->rx_buffer[state->rx_write_ptr++] = rx_data;
    data_len++;
    if(state->bytes_left>1){
        state->bytes_left--;
        return;
    }
    // Try decoding the packet at various offsets until it succeeds, or
	// until we run out of data.
    for(;;){
        int res = try_decode_packet(state->rx_buffer + state->rx_read_ptr,
		data_len, state->process_func, &state->bytes_left);

		// More data is needed
		if (res == -2) {
			break;
		}

		if (res > 0) {
			data_len -= res;
			state->rx_read_ptr += res;
		} else if (res == -1) {
			// Something went wrong. Move pointer forward and try again.
			state->rx_read_ptr++;
			data_len--;
		}
    }
	// Nothing left, move pointers to avoid memmove
	if (data_len == 0) {
		state->rx_read_ptr = 0;
		state->rx_write_ptr = 0;
	}
}
/**
 * Try if it is possible to decode a packet from a buffer.
 *
 * @param buffer
 * The buffer to try from
 *
 * @param in_len
 * The length of the buffer
 *
 * @param process_func
 * Call this function with the decoded packet on success. Set to null
 * to disable.
 *
 * @param bytes_left
 * This many additional bytes are required to tell more about the packet.
 *
 * @return
 * >0: Success, number of bytes decoded from buffer (not payload length)
 * -1: Invalid structure
 * -2: OK so far, but not enough data
 */
static int try_decode_packet(unsigned char *buffer, unsigned int in_len,
		void(*process_func)(unsigned char *data, unsigned int len), int *bytes_left) {
	*bytes_left = 0;

	if (in_len == 0) {
		*bytes_left = 1;
		return -2;
	}

	bool is_len_8b = buffer[0] == 2;
	unsigned int data_start = buffer[0];

#if PACKET_MAX_PL_LEN > 255
	bool is_len_16b = buffer[0] == 3;
#else
#define is_len_16b false
#endif

#if PACKET_MAX_PL_LEN > 65535
	bool is_len_24b = buffer[0] == 4;
#else
#define is_len_24b false
#endif

	// No valid start byte
	if (!is_len_8b && !is_len_16b && !is_len_24b) {
		return -1;
	}

	// Not enough data to determine length
	if (in_len < data_start) {
		*bytes_left = data_start - in_len;
		return -2;
	}

	unsigned int len = 0;

	if (is_len_8b) {
		len = (unsigned int)buffer[1];

		// No support for zero length packets
		if (len < 1) {
			return -1;
		}
	} else if (is_len_16b) {
		len = (unsigned int)buffer[1] << 8 | (unsigned int)buffer[2];

		// A shorter packet should use less length bytes
		if (len < 255) {
			return -1;
		}
	} else if (is_len_24b) {
		len = (unsigned int)buffer[1] << 16 |
				(unsigned int)buffer[2] << 8 |
				(unsigned int)buffer[3];

		// A shorter packet should use less length bytes
		if (len < 65535) {
			return -1;
		}
	}

	// Too long packet
	if (len > PACKET_MAX_PL_LEN) {
		return -1;
	}

	// Need more data to determine rest of packet
	if (in_len < (len + data_start + 3)) {
		*bytes_left = (len + data_start + 3) - in_len;
		return -2;
	}

	// Invalid stop byte
	if (buffer[data_start + len + 2] != 3) {
		return -1;
	}

	unsigned short crc_calc = crc16(buffer + data_start, len);
	unsigned short crc_rx = (unsigned short)buffer[data_start + len] << 8
							| (unsigned short)buffer[data_start + len + 1];

	if (crc_calc == crc_rx) {
		if (process_func) {
			process_func(buffer + data_start, len);
		}

		return len + data_start + 3;
	} else {
		return -1;
	}
}
#endif
/**
 * Try if it is possible to decode a packet from a buffer.
 *
 * @brief decode packet in RX
 * start address & size_len
 * @param data
 * The data buffer to try from
 *
 * @param in_len
 * The length of the buffer
 *
 * @param process_func
 * Call this function with the decoded packet on success. Set to null
 * to disable.
 *
 * @param bytes_left
 * This many additional bytes are required to tell more about the packet.
 *
 * @return
 * >0: Success, number of bytes decoded from buffer (not payload length)
 * -1: Invalid structure
 * -2: OK so far, but not enough data
 */
void decodeCWRXpacket(uint8_t *data,int32_t in_len){
    //static int32_t len; //文件的总长度
    //static uint32_t APPAddr;
    uint8_t pageNum=255;
	int32_t num=0;
    Descramble(data,in_len);
    for(int i=1;i<in_len;i++){
        switch(data[i]){
            //case 0x06:      //表示主机收到信号 在准备中
            //    break;
            //case 0:     //表示后面没有数据了
            //    break;
			case 'r':	//复位信号 直接跳转到新程序的flash开始执行程序	
				flash_helper_jump_to_APP();
				break;
			case 'n':	//表示本次升级的数量
                num = ((int32_t)data[i+1])|((int32_t)data[i+2]<<1);
                i += 2;
				break;
            //case 'l':   //i 表示这是告诉设备升级文件的长度 单位byte 占2字节
            //    len = ((int32_t)data[i+1])|((int32_t)data[i+2]<<1);
            //    i += 2;
            //break;
            //case 'a':   //a 表示告诉设备升级文件要升级的地址 设备转到该地址升级 占4字节
            //    APPAddr = ((int32_t)data[i+1])|((int32_t)data[i+2]<<1)|((int32_t)data[i+3]<<1)|((int32_t)data[i+4]<<1);
            //    i += 4;
            //break;
            case 'p':   //p 告诉设备待升级的page 共128page 每次升级一个page 512byte  擦除对应的page
                pageNum = data[i+1];
                i += 1;
                /* Erase the FLASH pages */
                erase_page(pageNum,1);
                //FLASH_UnlockPages(pageNum*FLASH_PAGE_SIZE, pageNum*FLASH_PAGE_SIZE));
                //FLASH_ErasePages(pageNum*FLASH_PAGE_SIZE, pageNum*FLASH_PAGE_SIZE));
            break;  
            case 'd':   //data 表示升级的数据 每次升级一个page 512byte
				if((pageNum<128)&&(num>0)&&(num<513)){	//最多一个page
					write_data(pageNum,&data[i+1],num);
				}
				i += num;	//直接结束
            break;
			default:
			break;
        }
    }
}
/***
 * @brief 解密扰码 还原正确的数据 第一个byte是本次扰码的随机数
 * @param data buff
 * @param in_len buff length
 * 
*/
void Descramble(uint8_t *data,int32_t in_len){
    uint8_t random = data[0]^0x35;    //还原随机数
    uint8_t sramble = 0x21; //扫码种子
    uint8_t Out;    //输出值
    //随机数做扰码种子
    for(int j=1;j<in_len;j++){
        Out = 0;
        for(int i=0;i<8;i++){
            Out >>= 1;
            if(random&0x01){
                random ^= (random>>1)^sramble;
                Out |= 0x80;
            }else{
                random >>= 1;
            }
        }
        data[j] ^= Out;
    }
}
